package com.lxf.clouduser.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lxf.clouduser.bean.GroupBean;
import com.lxf.clouduser.bean.UserBean;
import com.lxf.clouduser.bean.UserMsgBean;
import com.lxf.clouduser.bean.UserServeBean;
import com.lxf.clouduser.mapper.*;
import com.lxf.clouduser.service.UserServeService;
import com.lxf.clouduser.utils.RedisUtils;
import com.lxf.clouduser.utils.SendNettyMsgUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 罗兴发
 * @data 2025/6/25 9:22
 * @description：客服服务-业务实现层
 */
@Service
@Slf4j
public class UserServeServiceImpl implements UserServeService {
    @Resource
    UserServeMapper userServeMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UserServeItemRepository userServeItemRepository;
    @Resource
    private UserItemRepository userItemRepository;
    @Resource
    private SendNettyMsgUtils sendNettyMsgUtils;
    @Resource
    private UserMsgItemRepository userMsgItemRepository;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    //redisson分布式锁
    private final RedissonClient redissonClient;

    private final static String LOCK = "I_AM_USER_SERVER_LOCK";

    public UserServeServiceImpl(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }


    /**
     * 在线只能客服请求（用户使用，客服不能使用）
     * @param json
     * @param request
     * @return
     */
    @Override
    public String startNotArtificialServe(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        // 获取请求凭证,凭证中存放用户ID和用户名，存放格式为：userId_userName
        String secretToken = request.getHeader("secretToken");

        // 获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            // 截取请求头中存储的用户ID
            int secretTokenIndex = secretToken.lastIndexOf(":");
            String userIdSub = secretToken.substring(secretTokenIndex+1);
            Integer userId = Integer.valueOf(userIdSub);//用户ID

            // 时间规格化
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String addTime = sf.format(new Date());

            // 商品编码
            String goodCode = json.getString("good_code");

            // 用户诉求
            String reqContent = json.getString("req_content");

            // 从ES中搜索文件进行智能回复

            // 需要从feign中获取产品信息，用以作答

        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 该接口只能是用户使用，客服不能使用
     * @param json
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startArtificialServe(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        //获取请求凭证,凭证中存放用户ID和用户名，存放格式为：userId_userName
        String secretToken = request.getHeader("secretToken");

        //获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            //截取请求头中存储的用户ID
            int secretTokenIndex = secretToken.lastIndexOf(":");
            String userIdSub = secretToken.substring(secretTokenIndex+1);
            Integer userId = Integer.valueOf(userIdSub);//用户ID
            //时间规格化
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String addTime = sf.format(new Date());
            //用户诉求
            String reqContent = json.getString("req_content");
            List<UserServeBean> list = new ArrayList<>();
            //对象实例化
            UserServeBean serve = new UserServeBean();
            serve.setUserId(userId);
            serve.setReqContent(reqContent);
            serve.setAddTime(addTime);

            //list封装
            list.add(serve);

            //更新操作
            int flag = userServeMapper.addArtificialServe(list);
            if (flag<0){
                log.info("人工服务发起失败");
                js.put("code",401);
                js.put("msg","The Current Customer Service Is Busy");
            }else {
                log.info("人工服务发起成功");
                js.put("code",200);
                js.put("msg","Success");

                //存储到es中
                userServeItemRepository.save(serve);

                //捕捉异常情况
                try {
                    //查询用户信息
                    Optional<UserBean> u1 = userItemRepository.findById(userIdSub);
                    if (u1.isPresent()){
                        UserBean user = u1.get();
                        //消息通知内容
                        String msg = "用户：【"+user.getUserName()+"】于"+addTime+"发起人工客服请求，咨询内容为：【"+reqContent+"】，请相关客服尽快接待.....";
                        //查询所有是客服的用户
                        List<UserBean> list2 = userItemRepository.findUserBeanByIsKf(1);
                        for (UserBean u:list2) {
                            //给所有客服发一条通知，有人需要咨询服务
                            sendNettyMsgUtils.pushMsgToUser(2,"1",String.valueOf(u.getUserId()),msg);
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 该接口只能是客服使用，非客服的用户不能试用
     * @param json
     * @param request
     * @return
     */
    @Override
    public String getIsNotServe(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        //获取请求凭证,凭证中存放用户ID和用户名，存放格式为：userId_userName
        String secretToken = request.getHeader("secretToken");

        //获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            Integer isServe = json.getInteger("is_serve");//赛选服务状态
            String reqContent = json.getString("req_content");//需要咨询的相关内容
            List<SearchHit<UserServeBean>> list = userServeItemRepository.findUserServeBeanByIsServeAndReqContent(isServe,reqContent);
            for (SearchHit<UserServeBean> user:list) {
                //客服ID和用户ID
                Integer kfUserId = user.getContent().getKfUserId();
                Integer userId = user.getContent().getUserId();
                //查询两者的聊天记录，并存放到服务记录中,为帮助后来者如何服务用户
                List<SearchHit<UserMsgBean>> list1 = userMsgItemRepository.findUserMsgBeanByFromUserIdAndToUserId(kfUserId, userId);
                List<SearchHit<UserMsgBean>> list2 = userMsgItemRepository.findUserMsgBeanByFromUserIdAndToUserId(userId,kfUserId);
                List<UserMsgBean> msgList = new ArrayList<>();
                // 复制第一个数组到 msgList
                System.arraycopy(list1, 0, msgList, 0, list1.size());
                // 复制第二个数组到 msgList
                System.arraycopy(list2, 0, msgList, list1.size(), list2.size());
                user.getContent().setMsgList(msgList);
            }
            js.put("code",200);
            js.put("msg","Success");
            js.put("data",list);
        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 只能客服使用，用户不能使用
     * @param json
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)//开启事务
    public String respUserServe(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        //获取请求凭证
        String secretToken = request.getHeader("secretToken");

        //获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            //截取请求头中存储的用户ID
            int secretTokenIndex = secretToken.lastIndexOf(":");
            String userIdSub = secretToken.substring(secretTokenIndex+1);
            Integer userId = Integer.valueOf(userIdSub);//用户ID

            //消息
            String msg = "";
            Integer userId1 = null;
            RLock rLock = redissonClient.getLock(LOCK);
            try {
                UserBean userBean = userItemRepository.findById(userIdSub).get();
                if (1==userBean.getIsKf()){
                    //获取锁,持有锁时间10秒，十秒后未处理完，则自动释放锁，避免死锁
                    rLock.lock(10, TimeUnit.SECONDS);
                    String serveId = json.getString("serve_id");
                    UserServeBean userServe = userServeMapper.getUserServeByServeId(serveId);
                    if (null!=userServe){
                        Integer isServe = userServe.getIsServe();

                        //发服务请求的用户ID
                        userId1 = userServe.getUserId();

                        if (0==isServe){
                            userServe.setIsServe(1);//服务中
                            userServe.setKfUserId(userId);//提供人工咨询的客服ID
                            //更新数据库响应数据
                            int flag = userServeMapper.updateUserServe(userServe);
                            if (flag<0){
                                log.info("更新失败");
                                js.put("code",401);
                                js.put("msg","fails");
                            }else {
                                log.info("更新成功");
                                js.put("code",200);
                                js.put("msg","Success");

                                //更新ES中的服务状态和提供人工服务的客服
                                userServeItemRepository.save(userServe);

                                //添加客服10积分（以此作为公司客服KPI要求）
                                userMapper.updateUserPointsById(userId, 10);

                                //发送的消息内容
                                msg = "我是您的专属客服，工号："+userBean.getKfCode()+"，很高兴为您服务！";
                            }
                        }else {
                            js.put("code",201);
                            js.put("msg","The Current Request Has Already Been Received By Someone");
                        }
                    }else {
                        js.put("code",201);
                        js.put("msg","The System Exception!!!!!");
                    }
                }else {
                    js.put("code",402);
                    js.put("msg","Not Operable Without Customer Service");
                }
            }catch (Exception e){
                String message = e.getMessage();
                js.put("code",500);
                js.put("msg",message);
            }finally {
                //释放锁
                rLock.unlock();
            }
            //需要给用户发送一条消息，告知用户哪个客服为他服务
            if (!"".equals(msg))sendNettyMsgUtils.pushMsgToUser(1,userIdSub,String.valueOf(userId1),msg);
        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

    /**
     * 用户主动取消人工客服
     * 该接口只能用户使用，客服不可使用
     * @param json
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String setUserServe(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        //获取请求凭证
        String secretToken = request.getHeader("secretToken");

        //获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            //截取请求头中存储的用户ID
            int secretTokenIndex = secretToken.lastIndexOf(":");
            String userIdSub = secretToken.substring(secretTokenIndex+1);
            String serverId = json.getString("server_id");
            try {
                Optional<UserServeBean> serve = userServeItemRepository.findById(serverId);
                if (serve.isPresent()) {
                    UserServeBean userServe = serve.get();
                    userServe.setIsServe(3);
                    //更新数据库
                    int flag = userServeMapper.updateUserServe(userServe);
                    if (flag < 0) {
                        log.info("更新失败");
                        js.put("code", 401);
                        js.put("msg", "fails");
                    } else {
                        log.info("更新成功");
                        js.put("code", 200);
                        js.put("msg", "Success");

                        //更新ES中的服务状态和提供人工服务的客服
                        userServeItemRepository.save(userServe);

                        //发送的消息内容
                        String msg = "您已取消人工客服请求";

                        //需要给用户发送一条在线消息消息
                        sendNettyMsgUtils.pushMsgToUser(1,"1" ,userIdSub , msg);
                    }
                }
            }catch (Exception e){
                String message = e.getMessage();
                js.put("code",500);
                js.put("msg",message);
            }
        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

    @Override
    public String getServeByContent(JSONObject json, HttpServletRequest request) {
        JSONObject js = new JSONObject();

        //获取请求凭证
        String secretToken = request.getHeader("secretToken");

        //获取redis中缓存的token
        Object o = redisUtils.get(secretToken);
        if (null!=o){
            String reqContent = json.getString("req_content");
            Integer page = json.getInteger("page");
            Integer size = json.getInteger("size");

            // 计算初始页
            Integer startPage = (page-1)*size;

            // 1. 构建查询条件
            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                    .withQuery(QueryBuilders.multiMatchQuery(reqContent, "reqContent"))
                    .withPageable(PageRequest.of(startPage, size));

            // 2. 添加高亮配置
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("reqContent")
                    .preTags("<span style='color:red'>")
                    .postTags("</span>");
            queryBuilder.withHighlightBuilder(highlightBuilder);

            // 3. 执行查询
            SearchHits<UserServeBean> hits = elasticsearchRestTemplate
                    .search(queryBuilder.build(), UserServeBean.class);

            // 4. 处理高亮结果
            List<UserServeBean> list = hits.stream()
                    .map(hit -> {
                        UserServeBean doc = hit.getContent();
                        Map<String, List<String>> highlightFields = hit.getHighlightFields();
                        highlightFields.forEach((field, texts) -> {
                            try {
                                Field declaredField = doc.getClass().getDeclaredField(field);
                                declaredField.setAccessible(true);
                                declaredField.set(doc, texts.get(0));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        });
                        return doc;
                    }).collect(Collectors.toList());

            // 7. 构造分页结果
            PageImpl<UserServeBean> serveBeans = new PageImpl<>(list, PageRequest.of(startPage, size), hits.getTotalHits());

            js.put("data",serveBeans);
            js.put("code", 200);
            js.put("msg", "Success");
        }else {
            js.put("code",400);
            js.put("msg","The Current Request is Invalid");
        }
        return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
    }

}
